package cn.zhaopin.starter.security.service.impl;

import cn.zhaopin.starter.security.basic.CodeException;
import cn.zhaopin.starter.security.basic.UserContext;
import cn.zhaopin.starter.security.common.SecurityConstant;
import cn.zhaopin.starter.security.service.SecurityUserDetailService;
import cn.zhaopin.starter.security.user.SecurityContextHolder;
import cn.zhaopin.starter.security.wechat.WeChatMpSession;
import cn.zhaopin.starter.security.wechat.WeWork3rdUserInfo;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Primary;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Description: 通用安全用户服务
 *
 * @author zuomin (myleszelic@outlook.com)
 * @date: 2021/09/24-13:53
 */
@Primary
@Service
public class GenericSecurityUserService implements SecurityUserDetailService, InitializingBean, ApplicationContextAware {

    private ApplicationContext applicationContext;

    private Set<SecurityUserDetailService> securityUserServices;

    @Override
    public boolean support(String path) {
        return true;
    }

    /**
     * 当前可供执行的service
     * @return
     */
    private SecurityUserDetailService userService() {
        String pathValue = SecurityContextHolder.getValue(SecurityConstant.PATH_KEY);
        for (SecurityUserDetailService securityUserDetailService : securityUserServices) {
            if (securityUserDetailService.support(pathValue)) {
                return securityUserDetailService;
            }
        }
        throw CodeException.builder()
                .code(SecurityConstant.SECURITY_USER_DETAIL_SERVICE_NOT_FOUND)
                .msg("SecurityUserDetailService not match path : " + pathValue).build();
    }

    @Override
    public Boolean checkBindDevice(String phoneNumber, String deviceUuid) {
        return userService().checkBindDevice(phoneNumber, deviceUuid);
    }

    @Override
    public Boolean bindDevice(String phoneNumber, String deviceUuid, String osName, String osVersion) {
        return userService().bindDevice(phoneNumber, deviceUuid, osName, osVersion);
    }

    @Override
    public Void loginSuccessful(Authentication auth) {
        return userService().loginSuccessful(auth);
    }

    @Override
    public WeWork3rdUserInfo get3rdUserInfo(String code, String loginType) {
        return userService().get3rdUserInfo(code, loginType);
    }

    @Override
    public Boolean save3rdUserDetail(String userTicket) {
        return userService().save3rdUserDetail(userTicket);
    }

    @Override
    public WeChatMpSession getWeChatMpSession(String codeReq) {
        return userService().getWeChatMpSession(codeReq);
    }

    @Override
    public Map decryptWeChatMpUserInfo(String encryptData, String sessionKey, String iv) {
        return userService().decryptWeChatMpUserInfo(encryptData, sessionKey, iv);
    }

    @Override
    public UserContext findUserByUnionId(String unionId) {
        return userService().findUserByUnionId(unionId);
    }

    @Override
    public UserContext findUserByWeWork3rdUserId(String ewCorpId, String ewUserId) {
        return userService().findUserByWeWork3rdUserId(ewCorpId, ewUserId);
    }

    @Override
    public UserContext bindWeChatMpPhone(String sessionKey, String userData, String userIv, String phoneData, String phoneIv){
        return userService().bindWeChatMpPhone(sessionKey, userData, userIv, phoneData, phoneIv);
    }

    @Override
    public UserContext findUserByPhone(String phoneNumber) {
        return userService().findUserByPhone(phoneNumber);
    }

    @Override
    public void afterPropertiesSet() {
        Map<String, SecurityUserDetailService> securityUserServiceMap = applicationContext.getBeansOfType(SecurityUserDetailService.class);
        // 过滤掉自身
        securityUserServices = securityUserServiceMap.values().stream().filter(securityUserServices -> securityUserServices != this).collect(Collectors.toSet());
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
